/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 86186
 * Date: 2023-09-11
 * Time: 21:49
 */
//懒汉模式
/* class Singleton1 {
     private static Singleton1 instance = null;

     //因为这个方法既有对变量的读取也有对变量的修改，所以可能会发生线程安全问题
     public static Singleton1 getInstance() {
         if(instance == null) {
             instance = new Singleton1();
         }

         return instance;
     }

     private Singleton1() {}
}*/

/*
虽然对读操作和修改操作进行加锁可以保证线程的安全性，但是发生线程不安全的时候只会在instance为null的时候，也就是
第一次调用getInstance的时候，其他情况的时候并不会发生线程不安全的情况，那么其他情况下加锁操作就会显得很多余，
不仅如此，如果加锁的话，还会导致线程阻塞等待，减慢代码运行速度
 */
/*class Singleton1 {
    private static Singleton1 instance = null;

    //对读取变量和修改变量进行加锁操作，使之成为一个整体，也就是具有原子性
    public static Singleton1 getInstance() {
        synchronized (Singleton1.class) {
            if(instance == null) {
                instance = new Singleton1();
            }
        }

        return instance;
    }

    private Singleton1() {}
} */

/*class Singleton1 {
    private static Singleton1 instance = null;

    public static Singleton1 getInstance() {

        //为了防止多余的加锁操作，我们可以在外面在加上一个判断条件，判断是否需要加锁
        //当两个线程同时进入第一个if判断条件的时候，会有一个线程先拿到锁，这个拿到锁的线程就会创建Singleton实例对象
        //而那个没拿到锁的线程就会进入阻塞等待，当这个线程拿到锁的时候，instance已经有实例对象了，那么第二个if
        //判断就起作用了，这又保证了单例模式的实现
        if(instance == null) {
            synchronized (Singleton1.class) {
                if(instance == null) {
                    instance = new Singleton1();
                }
            }
        }

        return instance;
    }

    private Singleton1() {}
}*/

/*
虽然解决了原子性的问题，但是还会发生指令重排序的问题。
因为创建对象可以分为三个步骤：
1.申请内存空间
2.在内存空间上构造对象（构造方法）
3.被内存地址赋值给instance引用

在线程t1中，如果1、2、3的顺序因为指令重排序而变成了1、3、2
那么当线程t2执行的时候因为instance引用已经被复制了，那么instance就不为null了，第一个if判断不成立，直接返回instanc
虽然instance不为null，但是由于这块空间没有被初始化，所以也会出现问题，这时就需要使用volatile关键字来阻止指令重排序的发生
 */
class Singleton1 {
    private volatile static Singleton1 instance = null;

    public static Singleton1 getInstance() {

        if(instance == null) {
            synchronized (Singleton1.class) {
                if(instance == null) {
                    instance = new Singleton1();
                }
            }
        }

        return instance;
    }

    private Singleton1() {}
}

public class Demo2 {
    Singleton1 instance = Singleton1.getInstance();
}
